﻿using System;
using System.Collections.Generic;
using System.Text;
using ETModel;

namespace ETHotfix {
    /// <summary>
    /// 会话拓展操作
    /// </summary>
    public static class SessionHelper {

        /// <summary>
        /// gate服务器的玩家断线重连
        /// </summary>
        /// <param name="gateSession">在gate服务器,玩家的会话</param>
        /// <param name="rawGatePlayer">之前用的GatePlayer</param>
        public static GatePlayer GatePlayerReconnect(this Session gateSession, GatePlayer rawGatePlayer) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.Gate)) {
                throw new Exception("本方法需要在Gate服务器上调用!");
            }

            //将新的session关联给玩家
            rawGatePlayer.Parent = gateSession;

            //当前会话加玩家管理组件
            gateSession.AddComponent<GateClientSessionPlayerComponent>().Player = rawGatePlayer;

            //将等待重连组件里的等待任务清除
            Game.Scene.GetComponent<GatePlayerWaitReconnectComponent>()?.GatePlayerReconnect(rawGatePlayer);

            return rawGatePlayer;
        }
        /// <summary>
        /// gate服务器的玩家登录成功
        /// </summary>
        /// <param name="gateSession">在gate服务器,玩家的会话</param>
        /// <param name="setGatePlayerUserObject">给GatePlayer设置的用户自定义对象</param>
        public static GatePlayer GatePlayerLoginSuccess(this Session gateSession, object setGatePlayerUserObject) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.Gate)) {
                throw new Exception("本方法需要在Gate服务器上调用!");
            }

            GatePlayer player = ComponentFactory.CreateWithParent<GatePlayer>(gateSession);
            player.UserObject = setGatePlayerUserObject;
            //登录成功后,给这个玩家创建邮筒,在进入地图的流程里,会把玩家的实例ID发给Map服务器,Map服务器用作actorId使用,直接把消息发到Gate玩家的邮筒里
            player.AddComponent<MailBoxComponent, string>(MailboxType.GatePlayerRelayToClient);
            //加到全局Gate玩家管理
            Game.Scene.GetComponent<GatePlayersComponent>().Add(player);
            //当前会话加玩家管理组件
            gateSession.AddComponent<GateClientSessionPlayerComponent>().Player = player;

            return player;
        }
        /// <summary>
        /// 获取当前Gate会话关联的玩家对象
        /// </summary>
        /// <param name="gateSession">在gate服务器,玩家的会话</param>
        public static GatePlayer GetCurrGatePlayer(this Session gateSession) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.Gate)) {
                throw new Exception("本方法需要在Gate服务器上调用!");
            }

            var gateSessionPlayerComp = gateSession.GetComponent<GateClientSessionPlayerComponent>();
            if (gateSessionPlayerComp == null) return null;

            return gateSessionPlayerComp.Player;
        }
        /// <summary>
        /// 获取GatePlayer对应的会话
        /// </summary>
        /// <param name="gatePlayer"></param>
        /// <returns></returns>
        public static Session GetSession(this GatePlayer gatePlayer) {
            return gatePlayer.GetParent<Session>();
        }




        /// <summary>
        /// gate服务器的玩家成功登录到Map服务器
        /// </summary>
        /// <param name="gateSession">玩家在gate服务器的会话</param>
        /// <param name="MapPlayerInstanceId">需要拿到Map服务器的玩家实例ID</param>
        public static void GatePlayerLoginMapSuccess(this Session gateSession, long MapPlayerInstanceId) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.Gate)) {
                throw new Exception("本方法需要在Gate服务器上调用!");
            }

            gateSession.GetCurrGatePlayer().MapPlayerInstanceId = MapPlayerInstanceId;
        }





        /// <summary>
        /// map服务器上,玩家成功登录到map服务器(已登录重复调用会复用已存在对象)
        /// </summary>
        /// <param name="mapGateSession">在map服务器,来自gate服务器的会话</param>
        /// <param name="GatePlayerInstanceId">在Gate服务器上,玩家的实例ID</param>
        /// <param name="setMapPlayerUserObject">设置MapPlayer的用户自定义对象</param>
        public static async ETTask<MapPlayer> MapPlayerLoginSuccess(this Session mapGateSession, long GatePlayerInstanceId, object setMapPlayerUserObject) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.Map)) {
                throw new Exception("本方法需要在Map服务器上调用!");
            }
            var mapP = Game.Scene.GetComponent<MapPlayersComponent>();

            var mapPlayer = mapP.GetMapPlayerByGatePlayerInsId(GatePlayerInstanceId);
            if (mapPlayer != null) {
                //已经存在,则直接返回
                mapPlayer.UserObject = setMapPlayerUserObject;
                return mapPlayer;
            }

            mapPlayer = ComponentFactory.CreateWithParent<MapPlayer, long>(mapGateSession, GatePlayerInstanceId);
            mapPlayer.UserObject = setMapPlayerUserObject;
            //给这个单位挂上分发邮筒(消息会自动转到对应的IMActorHandler)
            await mapPlayer.AddComponent<MailBoxComponent>().AddLocation();

            mapP.Add(mapPlayer);

            return mapPlayer;
        }
        /// <summary>
        /// 在map服务器,收到gate客户端断开后重连的请求
        /// </summary>
        /// <param name="mapGateSession">在map服务器,来自gate服务器的会话</param>
        /// <param name="reconnectMapPlayerInsId">之前map服务器玩家实例ID</param>
        public static MapPlayer MapPlayerReconnect(this Session mapGateSession, long reconnectMapPlayerInsId) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.Map)) {
                throw new Exception("本方法需要在Map服务器上调用!");
            }

            var mapPlayer = Game.Scene.GetComponent<MapPlayersComponent>().Get(reconnectMapPlayerInsId);
            if (mapPlayer == null) {
                return null;
            }
            return mapPlayer;
        }





        /// <summary>
        /// 观众成功连接到观众服务器的操作,得到一个观众客户端对象
        /// </summary>
        /// <param name="audClientSession"></param>
        /// <param name="setUserObject"></param>
        /// <returns></returns>
        public static AudClient AudClientSuccess(this Session audClientSession, object setUserObject) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.MapAudience)) {
                throw new Exception("本方法需要在Aud服务器上调用!");
            }

            AudClient audClient = ComponentFactory.CreateWithParent<AudClient>(audClientSession);
            audClient.UserObject = setUserObject;
            //加到全局观众管理
            Game.Scene.GetComponent<AudClientsComponent>().Add(audClient);
            //当前会话加观众关联组件
            audClientSession.AddComponent<AudClientSessionComponent>().AudClient = audClient;

            return audClient;
        }
    }
}
